import NextAuth from 'next-auth'
import { UserRole } from '@prisma/client'
import { PrismaAdapter } from '@auth/prisma-adapter'

import prisma from '@/lib/prisma'
import authConfig from '@/auth.config'
import { getUserById } from '@/data/user'
import { getAccountByUserId } from '@/data/account'
import { getTwoFactorConfirmationByUserId } from '@/data/two-factor-confirmation'

export const { handlers, auth, signIn, signOut } = NextAuth({
    pages: {
        signIn: '/auth/login',
        error: '/auth/error',
    },
    events: {
        async linkAccount({ user }) {
            await prisma.user.update({
                where: { id: user.id },
                data: { emailVerified: new Date() }
            })
        }
    },
    callbacks: {
        async signIn({ user, account }) {
            // Allow OAuth without email verification
            if (account?.provider !== 'credentials') {
                return true
            }

            // Prevent sign in without email verification
            const existingUser = await getUserById(user.id ?? '')
            if (!existingUser?.emailVerified) {
                return false
            }

            // TODO: Add 2FA check
            if (existingUser.isTwoFactorEnabled) {
                const twoFactorConfimation = await getTwoFactorConfirmationByUserId(existingUser.id)
                if (!twoFactorConfimation) {
                    return false
                }

                // Delete two factor confirmation for next sign in
                await prisma.twoFactorConfirmation.delete({ where: { id: twoFactorConfimation.id } })
            }

            return true
        },

        async session({ session, token }) {
            if (session.user) {
                if (token.sub) {
                    session.user.id = token.sub
                }
                if (token.role) {
                    session.user.role = token.role as UserRole
                }
                if (token.isTwoFactorEnabled) {
                    session.user.isTwoFactorEnabled = token.isTwoFactorEnabled as boolean
                }
                session.user.name = token.name
                session.user.email = token.email as string
                session.user.isOAuth = token.isOAuth as boolean
            }
            return session
        },
        async jwt({ token }) {
            if (token.sub) {
                const existingUser = await getUserById(token.sub)
                if (existingUser) {
                    const existingAccount = await getAccountByUserId(existingUser.id)
                    token.name = existingUser.name
                    token.role = existingUser.role
                    token.email = existingUser.email
                    token.isOAuth = !!existingAccount
                    token.isTwoFactorEnabled = existingUser.isTwoFactorEnabled
                }
            }
            return token
        }
    },
    adapter: PrismaAdapter(prisma),
    session: { strategy: 'jwt' },
    ...authConfig
})